package com.wkbb.sports.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.wkbb.common.enums.SexTypeEnum;
import com.wkbb.sports.model.HlifeTrainStudent;
import com.wkbb.sports.model.HlifeTrainStudentAvg;
import com.wkbb.sports.model.HlifeTrainStudentDetail;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Statistics{
	
	private int maleTotal = 0, femaleTotal = 0;
	private int maleCount = 0, maleMinCount = 0, maleMaxCount = 0;
	private int femaleCount = 0, femaleMinCount = 0, femaleMaxCount = 0;
	private double maleScore = 0, maleMinScore = 0, maleMaxScore = 0;
	private double femaleScore = 0, femaleMinScore = 0, femaleMaxScore = 0;
	private int passingCount = 0;
	
	private double maleMedianCount = 0;

	private double femaleMedianCount = 0;
	
	private int[] femaleLevel = new int[12];
	private int[] maleLevel = new int[12];
	
	public void filter(byte sex, int count, double score)throws Exception{
		if(sex == 1) {
			maleTotal++;
			maleCount += count;
			if(maleMinCount == 0 || count < maleMinCount) {
				maleMinCount = count;
			}
			if(maleMaxCount == 0 || count > maleMaxCount) {
				maleMaxCount = count;
			}
			maleScore += score;
			if(maleMinScore == 0 || score < maleMinScore) {
				maleMinScore = score;
			}
			if(maleMaxScore == 0 || score > maleMaxScore) {
				maleMaxScore = score;
			}
			calculateScore(maleLevel, score);
		}else {
			femaleTotal++;
			femaleCount += count;
			if(femaleMinCount == 0 || count < femaleMinCount) {
				femaleMinCount = count;
			}
			if(femaleMaxCount == 0 || count > femaleMaxCount) {
				femaleMaxCount = count;
			}
			femaleScore += score;
			if(femaleMinScore == 0 || score < femaleMinScore) {
				femaleMinScore = score;
			}
			if(femaleMaxScore == 0 || score > femaleMaxScore) {
				femaleMaxScore = score;
			}
			
			calculateScore(femaleLevel, score);
		}
		
		if(score >= 60) {
			passingCount++;
		}
		
	}

	private void calculateScore(int[] level, double score) {
		for(int i = 0; i < level.length; i++) {
			int min = i * 10;
			int max = min + 10;
			if(score >= min && score < max) {
				level[i] = level[i] + 1;
				return;
			}
		}
	}
	
	

	public int getMaleCount() {
		return maleCount;
	}

	public int getFemaleCount() {
		return femaleCount;
	}

	public double getMaleScore() {
		return maleScore;
	}

	public double getFemaleScore() {
		return femaleScore;
	}

	public int getPassingCount() {
		return passingCount;
	}

	public int getMaleMinCount() {
		return maleMinCount;
	}

	public int getMaleMaxCount() {
		return maleMaxCount;
	}

	public int getFemaleMinCount() {
		return femaleMinCount;
	}

	public int getFemaleMaxCount() {
		return femaleMaxCount;
	}

	public double getMaleMinScore() {
		return maleMinScore;
	}

	public double getMaleMaxScore() {
		return maleMaxScore;
	}

	public double getFemaleMinScore() {
		return femaleMinScore;
	}

	public double getFemaleMaxScore() {
		return femaleMaxScore;
	}

	public int getMaleTotal() {
		return maleTotal;
	}

	public int getFemaleTotal() {
		return femaleTotal;
	}

	public int[] getFemaleLevel() {
		return femaleLevel;
	}

	public int[] getMaleLevel() {
		return maleLevel;
	}
	
	public double getMaleMedianCount() {
		return maleMedianCount;
	}

	public double getFemaleMedianCount() {
		return femaleMedianCount;
	}

	public double getPassingRate() {
		double total = femaleTotal + maleTotal;
		if(total <= 0) {
			return 0;
		}
		double passingRate = passingCount / total;
		log.info("passingCount:" + passingCount + ", total:" + total + ", passingRate:" + passingRate);
		return passingRate;
	}

	public void toMap(Map<String, Object> maps) throws Exception{
		Class<?> cls = this.getClass();
		for(Field fld : cls.getDeclaredFields()) {
			int mod = fld.getModifiers();
			if(Modifier.isStatic(mod)) {
				return;
			}
			String name = fld.getName();
			Class<?> type = fld.getType();
			if(type.isArray()) {
				Object value = fld.get(this);
				int len = Array.getLength(value);
				for(int i = 0; i < len; i++) {
					Object val = Array.get(value, i);
					maps.put(name + (i + 1), val);
				}
			}else {
				maps.put(name, fld.get(this));
			}
		}
	}
	
	static class ScoreCompare implements Comparator<HlifeTrainStudent>{
		@Override
		public int compare(HlifeTrainStudent std1, HlifeTrainStudent std2) {
			double rev= std1.getTotalScore() - std2.getTotalScore();
			if(rev > 0) {
				return 1;
			}else if(rev < 0) {
				return -1;
			}
			return (int)(std1.getStudentId() - std2.getStudentId());
		}
	}

	public void sortStudentScore(List<HlifeTrainStudent> students) {
		Set<HlifeTrainStudent> sortSet = new TreeSet<>(new ScoreCompare());
		sortSet.addAll(students);
		int order = 0;
		HlifeTrainStudent prev = null;
		for(HlifeTrainStudent student : sortSet) {
			order++;
//			if(prev != null && prev.getTotalScore() == student.getTotalScore()) {
//				student.setRanking(prev.getRanking());
//			}else {
//				student.setRanking(order);
//			}
			prev = student;
		}
	}
	
	public void sortStudentScoreByGender(List<HlifeTrainStudent> students, byte sex) {
		Set<HlifeTrainStudent> sortSet = new TreeSet<>(new ScoreCompare());
		for(HlifeTrainStudent student : students) {
			if(student.getSex() == sex) {
				sortSet.add(student);
			}
		}
		int order = 0;
		HlifeTrainStudent prev = null;
		for(HlifeTrainStudent student : sortSet) {
			order++;
//			if(prev != null && prev.getTotalScore() == student.getTotalScore()) {
//				student.setRankingInGender(prev.getRankingInGender());
//			}else {
//				student.setRankingInGender(order);
//			}
			prev = student;
		}
		if(sortSet.size() >= 2) {
			HlifeTrainStudent[] stus = sortSet.toArray(new HlifeTrainStudent[sortSet.size()]);
			int pos = stus.length / 2;
			double medianCount;
			if(stus.length % 2 == 0) {
				medianCount = getMedianCount(stus[pos - 1], stus[pos]);
			}else {
				medianCount = getMedianCount(stus[pos], stus[pos]);
			}
			if(sex == SexTypeEnum.MAN.getValue().byteValue()) {
				maleMedianCount = medianCount;
			}else {
				femaleMedianCount = medianCount;
			}
		}
	}
	
	public static Double getMedianCount(List<HlifeTrainStudent> students) {
		Set<HlifeTrainStudent> sortSet = new TreeSet<>(new ScoreCompare());
		sortSet.addAll(students);
		double medianCount = 0;
		HlifeTrainStudent[] stus = sortSet.toArray(new HlifeTrainStudent[sortSet.size()]);
		if(sortSet.size() >= 2) {
			int pos = stus.length / 2;
			if(stus.length % 2 == 0) {
				medianCount = getMedianCount(stus[pos - 1], stus[pos]);
			}else {
				medianCount = getMedianCount(stus[pos], stus[pos]);
			}
		}else if(sortSet.size() == 1) {
			medianCount = getMedianCount(stus[0], stus[0]);
		}
		return medianCount;
	}
	
	private static Double getMedianCount(HlifeTrainStudent stu1, HlifeTrainStudent stu2) {
		Double  count1 = Double.parseDouble(stu1.getAchievement());
		Double  count2 = Double.parseDouble(stu2.getAchievement());
		return (count1 + count2) / 2;
	}

	public HlifeTrainStudentAvg[] averageDetail(List<HlifeTrainStudentDetail> studentDetails) {
		HlifeTrainStudentAvg[] avgs = new HlifeTrainStudentAvg[CIRCLE_COUNT];
		for(int i = 0; i < avgs.length; i++) {
			avgs[i] = new HlifeTrainStudentAvg();
		}
		int[] total = new int[CIRCLE_COUNT];
		int[] maleTotal = new int[CIRCLE_COUNT];
		int[] femaleTotal = new int[CIRCLE_COUNT];
		for(HlifeTrainStudentDetail detail : studentDetails) {
//			int circle = detail.getSeqNo();
//			detail.setSpend(detail.getTimeStamp().intValue());
//			HlifeTrainStudentAvg avg = avgs[circle];
//			avg.setSpend(avg.getSpend() + detail.getSpend());
//			total[circle]++;
//			if(detail.getSex() == SexTypeEnum.MAN.getValue().byteValue()) {
//				avg.setMaleSpend(avg.getMaleSpend() + detail.getSpend());
//				maleTotal[circle]++;
//			}else {
//				avg.setFemaleSpend(avg.getFemaleSpend() + detail.getSpend());
//				femaleTotal[circle]++;
//			}
		}
		List<HlifeTrainStudentAvg> list = new ArrayList<>();
		for(int i = 0; i < CIRCLE_COUNT; i++) {
			HlifeTrainStudentAvg avg = avgs[i];
			if(total[i] > 0) {
				avg.setSpend(avg.getSpend() / total[i]);
				list.add(avg);
			}
			if(maleTotal[i] > 0) {
				avg.setMaleSpend(avg.getMaleSpend() / maleTotal[i]);
			}
			if(femaleTotal[i] > 0) {
				avg.setFemaleSpend(avg.getFemaleSpend() / femaleTotal[i]);
			}
		}
		return list.toArray(new HlifeTrainStudentAvg[list.size()]);
	}
	
	private final static int CIRCLE_COUNT = 600;
	
	
}
